package partialMiniAes;

import miniAES.assembly;
import miniAES.enCry;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class fiveMAES {
    public static void main(String[] args) {
     /*初始准备
     * 密钥：k_0=[0b1100,0b0011,0b1111,0b0000] k_1=[0b0011,0b0000,0b1111,0b1111]
     * 7个已知的明密文对
     * m1=[0b0,0b111,0b0,0b1001],c1=[0b110,0b111,0b1010,0b1000].
     * m2=[0b10,0b1101,0b1010,0b1010],c2=[0b1110,0b0,0b1100,0b1101].
     * m3=[0b10,0b11,0b1,0b1000],c3=[0b1111,0b111,0b101,0b1111].
     * m4=[0b1001,0b111,0b1101,0b100],c4=[0b1110,0b1000,0b100,0b0].
     * m5=[0b1101,0b111,0b1110,0b100],c5=[0b1,0b100,0b10,0b111].
     * m6=[0b11,0b111,0b11,0b110],c6=[0b100,0b101,0b1100,0b1000].
     * m7=[0b110,0b110,0b1,0b1010],c7=[0b101,0b10,0b110,0b1000].
     * */
     //已知明密文对
        byte [][] M={
                {0b0,0b111,0b0,0b1001},
                {0b10,0b1101,0b1010,0b1010},
                {0b10,0b11,0b1,0b1000},
                {0b1001,0b111,0b1101,0b100},
                {0b1101,0b111,0b1110,0b100},
                {0b11,0b111,0b11,0b110},
                {0b110,0b110,0b1,0b1010}
        };
        byte [][] C={
                {0b110,0b111,0b1010,0b1000},
                {0b1110,0b0,0b1100,0b1101},
                {0b1111,0b111,0b101,0b1111},
                {0b1110,0b1000,0b100,0b0},
                {0b1,0b100,0b10,0b111},
                {0b100,0b101,0b1100,0b1000},
                {0b101,0b10,0b110,0b1000}
        };
        //公共密钥字段3个半字节 以向后计算【即解密的猜测密钥构建表L】
          //这里得Kj从高比特位到底比特位对应于K0[0] K0[3] K1[0]
        for (int Kj = 0; Kj < 4096; Kj++) {
            //Kj转为半字节存储 subKeyJ[0]对应K0[0] subKeyJ[1]对应K0[3] subKeyJ[2]对应K1[0]
            byte [] subKeyJ=new byte[3];
            InterToNibble(Kj,subKeyJ,3);
            //assembly.printBin(subKeyJ,3);

            //存器中间值
            Map<Byte, Byte> minValS=new HashMap<>();
            //subKeyB表示向后计算的密钥
            byte [] subKeyB=new byte[1];
            //对于Kb的每一个取值向前计算得到中间的值
            for (int Kb = 0; Kb < 16; Kb++) {
                InterToNibble(Kb,subKeyB,1);
                byte minVal=bgetMinX0ToB(subKeyJ,subKeyB,C[0]);
                /*if (minVal==0b110&&subKeyJ[0]==0b1100&&subKeyJ[1]==0b0000&&subKeyJ[2]==0b0011){
                    assembly.printBin(subKeyJ,3);
                    assembly.printBin(subKeyB,1);
                }*/
                //建立L表
                minValS.put(minVal,subKeyB[0]);
            }
            for (int Kf = 0; Kf < 4096; Kf++) {
                byte [] subKeyF=new byte[3];
                InterToNibble(Kf,subKeyF,3);
                //猜测的密钥K0
                byte [] guessK0=new byte[4];
                //猜测的密钥K1
                byte [] guessK1=new byte[4];
                guessK0[0]=subKeyJ[0];
                guessK0[1]=subKeyF[0];
                guessK0[2]=subKeyF[1];
                guessK0[3]=subKeyJ[1];

                guessK1[0]=subKeyJ[2];
                guessK1[3]=subKeyF[2];

                byte minVal=bgetMinX0ToF(guessK0,guessK1,M[0]);
                /*if (minVal==0b110&&guessK0[0]==0b1100&&guessK0[1]==0b0011&&guessK0[2]==0b1111&&guessK0[3]==0b0000&&guessK1[0]==0b0011&&guessK1[3]==0b1111){
                    assembly.printBin(guessK0,4);
                    assembly.printBin(guessK1,4);
                }*/
                Byte K11=minValS.get(minVal);
                if (K11==null){
                }else {
                    int num=1;
                    byte[] K1one=new byte [1];
                    K1one[0]=K11;
                    for ( ;num <7 ; num++) {
                        byte minValF=bgetMinX0ToF(guessK0,guessK1,M[num]);
                        byte minValB=bgetMinX0ToB(subKeyJ,K1one,C[num]);
                        if (minValF!=minValB){
                            break;
                        }
                    }
                    if (num==7){
                        guessK1[1]=K1one[0];
                        assembly.printBin(guessK0,4);
                        assembly.printBin(guessK1,4);
                    }
                }
            }
        }


    }

    private static byte bgetMinX0ToF(byte[] guessK0, byte[] guessK1, byte[] bytes) {
        // 创建 bytes 数组的副本
        byte[] bytesCopy = Arrays.copyOf(bytes, bytes.length);
        //白化
        bytesCopy=assembly.keyAddition(bytesCopy,guessK0);
        //第一轮加密
        bytesCopy=enCry.oneEnCry(bytesCopy,guessK0);
        //第二轮
        bytesCopy=assembly.nibbleSub(bytesCopy);
        bytesCopy=assembly.shiftRow(bytesCopy);
        byte twoOut[]=new byte[4];
        assembly.mixColumn(bytesCopy,twoOut);
        byte temp0=twoOut[0];
        byte temp3=twoOut[3];
        temp0^=guessK1[0];
        temp3^=guessK1[3];
        //第三轮
        temp0=assembly.sBox[temp0];
        temp3=assembly.sBox[temp3];
        byte temp= (byte) (assembly.gfMultiplication((byte) 3,temp0)^assembly.gfMultiplication((byte) 2,temp3));
        return (byte) (temp^guessK0[0]);
    }

    private static Byte bgetMinX0ToB(byte[] subKeyJ, byte[] subKeyB, byte[] bytes) {
        byte temp1=bytes[0];
        byte temp2=bytes[3];
        temp1^=subKeyJ[0];
        temp2^=subKeyJ[1];
        temp1=assembly.inSbox[temp1];
        temp2=assembly.inSbox[temp2];
        //第五轮的逆
        temp1^=subKeyJ[2];
        temp2^=subKeyB[0];
        byte temp= (byte) (assembly.gfMultiplication((byte) 3,temp1)^assembly.gfMultiplication((byte) 2,temp2));

        //byte i = assembly.gfMultiplication((byte) 3, bytesCopy[0]) ^ assembly.gfMultiplication((byte) 2, bytesCopy[3]);
        //第4轮的逆
        return assembly.inSbox[temp];
    }

    //将subkey转为i个半字节
    private static void InterToNibble(int subkey, byte[] subKeyJ, int i) {
        for (int j = i-1; j >=0 ; j--) {
            subKeyJ[j]= (byte) (subkey&0b1111);
            subkey>>=4;
        }
    }

    //

}
